<?php
require_once 'Junction/Clause.php';
require_once 'Junction/Clause/Where.php';
require_once 'Junction/Core/Factory.php';
require_once 'Junction/Mapping/References.php';
require_once 'Junction/Mapping/Table.php';
require_once 'Junction/Query.php';
require_once 'Junction/Query/Delete.php';
require_once 'Junction/Query/Insert.php';
require_once 'Junction/Query/Select.php';
require_once 'Junction/Query/Update.php';
require_once 'Junction/Tracker.php';
require_once 'Junction/Utils/Reflection.php';

/**
 * Represent a single mapping file and corresponding operations.
 *
 */
class Junction_Mapping {

    private $_name;

    /**
     * @var Junction_Mapping_References
     */
    private $_references;

    /**
     * @var Junction_Mapping_Table
     */
    private $_table;

    public function __construct($classname, Junction_Mapping_Table $table, Junction_Mapping_References $refs) {
        $this->_name = $classname;
        $this->_table = $table;
        $this->_references = $refs;
    }
    
    #START Mapping query methods

    public function buildWhereClause($object) {
        $clause = new Junction_Clause_Where($this->_table->translateQuery(
        $this->_table->getKeyProperty() . ' = ?'),
            array($this->getValueFor($object,
            $this->_table->getKeyProperty())));
        return $clause;
    }
    
    #END
    
    #START Mapping utility methods

    public function getName() {
        return $this->_name;
    }
    
    public function getTablename() {
        return $this->_table->getName();
    }
    
    public function buildQueryUsing(Junction_Query $builder, $object = null) {
        return $this->_table->buildQueryUsing($builder, $object);
    }
    
    /**
     * @return Iterator
     */
    public function getProperties() {
        $properties = new AppendIterator();
        $properties->append($this->_table->getProperties());
        $properties->append($this->_references->getProperties());
        return $properties;
    }
    
    public function getScalarProperties() {
        return $this->_table->getProperties();
    }
    
    public function getReferences() {
        return $this->_references->getIterator();
    }
    
//    private function hasBeenSaved($object) {
//        return ($this->getValueFor($object,
//        $this->_table->getKeyProperty()) != null);
//    }

    public function getValueFor($object, $property) {
        return Junction_Utils_Reflection::getValueFor($object, $property);
    }
    
    public function getValueForColumn($object, $column) {
        return Junction_Utils_Reflection::getValueFor($object, $this->columnToProperty($column));
    }

    public function setValueFor($object, $property, $value) {
        Junction_Utils_Reflection::setValueFor($object, $property, $value);
    }

    public function setValueForColumn($object, $column, $value) {
        Junction_Utils_Reflection::setValueFor($object, $this->columnToProperty($column), $value);
    }
    
    public function getKeyProperty() {
        return $this->_table->getKeyProperty();
    }
    
    public function getKeyColumn() {
        return $this->_table->propertyToColumn($this->getKeyProperty());
    }
    
    /**
     * @param String $property
     * @return boolean
     */
    private function contains($property) {
        if ($this->_table->contains($property)) {
            return true;
        }
        return $this->_references->contains($property);
    }

    /**
     * @param String $property
     * @return boolean
     */
    private function isReference($property) {
        return $this->_references->contains($property);
    }

    /**
     * @param String $property
     * @return Junction_Mapping_DirectReference
     */
    private function propertyToReference($property) {
        return $this->_references->propertyToReference($property);
    }

    /**
     * @param String $column
     * @return String
     */
    public function columnToProperty($column) {
        return $this->_table->columnToProperty($column);
    }
    
    #END
}
?>